package com.kinyx.framework.db.sentence.res;

import java.util.List;

import javax.persistence.metamodel.SingularAttribute;

import com.kinyx.framework.db.configs.DBConfigs;
import com.kinyx.framework.db.sentence.CompareType;
import com.kinyx.framework.db.sentence.LikeType;
import com.kinyx.framework.db.sentence.defines.Params;
import com.kinyx.framework.enums.impl.ErrorCodeX;
import com.kinyx.framework.exception.KRuntimeException;

/**
 * 关联表子句
 */
public class JoinTable extends Table implements Params {

	/** 持有者 */
	private final KSELECT holder;
	/** 连接类型 */
	private final String joinType;
	/** 条件子句 */
	private Condition condition;

	JoinTable(final KSELECT holder, final Table table, final String joinType, final int tableIdx) {
		super(table, tableIdx);
		this.holder = holder;
		this.joinType = joinType;
	}

	@Override
	public String getSentence(final DBConfigs configs, final boolean isSQL, final boolean withTableAlias) {
		return String.format(" %s %s ON %s", this.joinType, super.getSentence(configs, isSQL, withTableAlias), this.condition.getSentence(configs, isSQL, withTableAlias));
	}

	@Override
	public List<Object> getParams() { return this.condition.getParams(); }

	// ============================================ condition ============================================ //
	/**
	 * 关联表条件子句
	 * @param condition 条件子句
	 * @return 查询语句
	 */
	public KSELECT on(final Condition condition) {
		if (this.condition != null) { throw new KRuntimeException(ErrorCodeX.RepeatCall); }
		this.condition = condition;
		return this.holder;
	}

	// ============================================ column = ? ============================================ //
	// ============================================ columnX = columnY ============================================ //
	/**
	 * 关联表条件子句
	 * @param column 列
	 * @param compareType 表达式类型
	 * @param param 参数或列
	 * @return 查询语句
	 */
	public KSELECT on(final Column column, final CompareType compareType, final Object param) {
		switch (compareType) {
			case EQ:
				return this.on(Condition.eq(column, param));
			case NEQ:
				return this.on(Condition.neq(column, param));
			case LT:
				return this.on(Condition.lt(column, param));
			case LTE:
				return this.on(Condition.lte(column, param));
			case GT:
				return this.on(Condition.gt(column, param));
			case GTE:
				return this.on(Condition.gte(column, param));
			default :
				throw new KRuntimeException(ErrorCodeX.NotImplemented);
		}
	}
	/**
	 * 关联表条件子句
	 * @param attr 属性
	 * @param compareType 表达式类型
	 * @param param 参数或列
	 * @return 查询语句
	 */
	public KSELECT on(final SingularAttribute<?, ?> attr, final CompareType compareType, final Object param) {
		return this.on(Res.toCol(attr), compareType, param);
	}

	// ============================================ columnX in () ============================================ //
	/**
	 * 关联表条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 查询语句
	 */
	public KSELECT on(final Column column, final boolean in, final String paramsStr) {
		if (in) {
			return this.on(Condition.in(column, paramsStr));
		} else {
			return this.on(Condition.notIn(column, paramsStr));
		}
	}
	/**
	 * 关联表条件子句
	 * @param attr 属性
	 * @param in true：IN；false：NOT IN；
	 * @param paramsStr 参数，使用特殊分隔[{@link com.kinyx.framework.Configs#specialSeparator}]符切分。
	 * @return 查询语句
	 */
	public KSELECT on(final SingularAttribute<?, ?> attr, final boolean in, final String paramsStr) {
		return this.on(Res.toCol(attr), in, paramsStr);
	}

	/**
	 * 关联表条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsList 参数
	 * @return 查询语句
	 */
	public KSELECT on(final Column column, final boolean in, final List<String> paramsList) {
		if (in) {
			return this.on(Condition.in(column, paramsList));
		} else {
			return this.on(Condition.notIn(column, paramsList));
		}
	}
	/**
	 * 关联表条件子句
	 * @param attr 属性
	 * @param in true：IN；false：NOT IN；
	 * @param paramsList 参数
	 * @return 查询语句
	 */
	public KSELECT on(final SingularAttribute<?, ?> attr, final boolean in, final List<String> paramsList) {
		return this.on(Res.toCol(attr), in, paramsList);
	}

	/**
	 * 关联表条件子句
	 * @param column 列
	 * @param in true：IN；false：NOT IN；
	 * @param paramsArr 参数
	 * @return 查询语句
	 */
	public KSELECT on(final Column column, final boolean in, final String[] paramsArr) {
		if (in) {
			return this.on(Condition.in(column, paramsArr));
		} else {
			return this.on(Condition.notIn(column, paramsArr));
		}
	}
	/**
	 * 关联表条件子句
	 * @param attr 属性
	 * @param in true：IN；false：NOT IN；
	 * @param paramsArr 参数
	 * @return 查询语句
	 */
	public KSELECT on(final SingularAttribute<?, ?> attr, final boolean in, final String[] paramsArr) {
		return this.on(Res.toCol(attr), in, paramsArr);
	}

	// ============================================ like ? ============================================ //
	/**
	 * 关联表条件子句
	 * @param column 列
	 * @param like true：LIKE；false：NOT LIKE；
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 查询语句
	 */
	public KSELECT on(final Column column, final boolean like, final LikeType likeType, final String param) {
		if (like) {
			return this.on(Condition.like(column, likeType, param));
		} else {
			return this.on(Condition.notLike(column, likeType, param));
		}
	}
	/**
	 * 关联表条件子句
	 * @param attr 属性
	 * @param like true：LIKE；false：NOT LIKE；
	 * @param likeType LIKE表达式类型
	 * @param param 参数
	 * @return 查询语句
	 */
	public KSELECT on(final SingularAttribute<?, ?> attr, final boolean like, final LikeType likeType, final String param) {
		return this.on(Res.toCol(attr), like, likeType, param);
	}

	// ============================================ isNull ============================================ //
	/**
	 * 关联表条件子句
	 * @param column 列
	 * @param isNull true：IS NULL；false：IS NOT NULL；
	 * @return 查询语句
	 */
	public KSELECT on(final Column column, final boolean isNull) {
		if (isNull) {
			return this.on(Condition.isNull(column));
		} else {
			return this.on(Condition.isNotNull(column));
		}
	}
	/**
	 * 关联表条件子句
	 * @param attr 属性
	 * @param isNull true：IS NULL；false：IS NOT NULL；
	 * @return 查询语句
	 */
	public KSELECT on(final SingularAttribute<?, ?> attr, final boolean isNull) {
		return this.on(Res.toCol(attr), isNull);
	}

}
